import CryptoJS from 'crypto-js'

const BLUFI_SERVICE_UUID = '0000FFFF-0000-1000-8000-00805F9B34FB'
const WRITE_CHARACTERISTIC_UUID = '0000FF01-0000-1000-8000-00805F9B34FB'
const NOTIFY_CHARACTERISTIC_UUID = '0000FF02-0000-1000-8000-00805F9B34FB'

class BleService {
	constructor() {
		this.deviceId = ''
		this.serviceId = ''
		this.writeCharacteristicId = ''
		this.notifyCharacteristicId = ''
	}

	// 初始化蓝牙
	async initBluetooth() {
		try {
			await wx.openBluetoothAdapter()
			await wx.startBluetoothDevicesDiscovery({
				services: [BLUFI_SERVICE_UUID]
			})
		} catch (error) {
			console.error('初始化蓝牙失败:', error)
			throw new Error('请开启蓝牙并授权')
		}
	}

	// 搜索设备
	async searchDevices() {
		return new Promise((resolve, reject) => {
			const devices = []

			wx.onBluetoothDeviceFound((res) => {
				res.devices.forEach(device => {
					if (!devices.find(d => d.deviceId === device.deviceId)) {
						devices.push(device)
					}
				})
			})

			setTimeout(async () => {
				await wx.stopBluetoothDevicesDiscovery()
				resolve(devices)
			}, 10000)
		})
	}

	// 连接设备
	async connectDevice(deviceId) {
		try {
			this.deviceId = deviceId

			await wx.createBLEConnection({
				deviceId: this.deviceId
			})

			const {
				services
			} = await wx.getBLEDeviceServices({
				deviceId: this.deviceId
			})

			this.serviceId = services.find(
				s => s.uuid.toUpperCase() === BLUFI_SERVICE_UUID
			)?.uuid

			if (!this.serviceId) {
				throw new Error('未找到指定服务')
			}

			const {
				characteristics
			} = await wx.getBLEDeviceCharacteristics({
				deviceId: this.deviceId,
				serviceId: this.serviceId
			})

			this.writeCharacteristicId = characteristics.find(
				c => c.uuid.toUpperCase() === WRITE_CHARACTERISTIC_UUID
			)?.uuid

			this.notifyCharacteristicId = characteristics.find(
				c => c.uuid.toUpperCase() === NOTIFY_CHARACTERISTIC_UUID
			)?.uuid

			if (!this.writeCharacteristicId || !this.notifyCharacteristicId) {
				throw new Error('未找到指定特征值')
			}

			await this.enableNotify()

		} catch (error) {
			console.error('连接设备失败:', error)
			throw error
		}
	}

	// 启用通知
	async enableNotify() {
		await wx.notifyBLECharacteristicValueChange({
			deviceId: this.deviceId,
			serviceId: this.serviceId,
			characteristicId: this.notifyCharacteristicId,
			state: true
		})
	}

	// 配网
	async startConfig(ssid, password) {
		try {
			// 1. 发送 SSID
			await this.sendDataWithRetry({
				type: 0x1,
				subtype: 0x2,
				data: this.encryptData(ssid)
			})

			// 2. 发送密码
			await this.sendDataWithRetry({
				type: 0x1,
				subtype: 0x3,
				data: this.encryptData(password)
			})

			// 3. 发送连接命令
			await this.sendDataWithRetry({
				type: 0x0,
				subtype: 0x3,
				data: new Uint8Array([0x01])
			})

			return this.waitForResult()

		} catch (error) {
			console.error('配网失败:', error)
			throw error
		}
	}

	// 字符串转字节数组
	stringToBytes(str) {
		const bytes = []
		for (let i = 0; i < str.length; i++) {
			console.log(i, 'i')
			const code = str.charCodeAt(i)
			console.log(code, 'code')
			if (code < 0x80) {
				bytes.push(code)
			} else if (code < 0x800) {
				bytes.push(0xc0 | (code >> 6))
				bytes.push(0x80 | (code & 0x3f))
			} else if (code < 0x10000) {
				bytes.push(0xe0 | (code >> 12))
				bytes.push(0x80 | ((code >> 6) & 0x3f))
				bytes.push(0x80 | (code & 0x3f))
			}
		}
		console.log(bytes, 'bytes')
		return new Uint8Array(bytes)
	}

	// 数据处理（不加密）
	encryptData(data) {
		return this.stringToBytes(data)
	}

	// 发送数据（带重试）
	async sendDataWithRetry(params, maxRetries = 3) {

		let lastError
		for (let i = 0; i < maxRetries; i++) {
			try {
				await this.sendData(params)
				return
			} catch (error) {
				lastError = error
				await new Promise(resolve => setTimeout(resolve, 1000))
			}
		}
		throw lastError
	}

	// 发送数据
	async sendData({
		type,
		subtype,
		data
	}) {
		const frame = this.buildFrame(type, subtype, data)

		await wx.writeBLECharacteristicValue({
			deviceId: this.deviceId,
			serviceId: this.serviceId,
			characteristicId: this.writeCharacteristicId,
			value: frame.buffer
		})
	}

	// 构建数据帧
	buildFrame(type, subtype, data) {
		console.log("type", type)
		console.log("subtype", subtype)
		console.log("data", data)
		const frameControl = (type << 2) | (subtype & 0x3)
		console.log("frameControl", frameControl)
		const dataLength = data ? data.length : 0
		console.log("dataLength", dataLength)
		const frame = new Uint8Array(4 + dataLength)
		frame[0] = frameControl
		frame[1] = 0
		frame[2] = dataLength & 0xFF
		frame[3] = (dataLength >> 8) & 0xFF

		if (data) {
			frame.set(data, 4)
		}
		console.log(frame, 'frame')
		return frame
	}

	// 等待配网结果
	waitForResult() {
		return new Promise((resolve, reject) => {
			const timeout = setTimeout(() => {
				reject(new Error('配网超时'))
			}, 30000)

			wx.onBLECharacteristicValueChange((res) => {
				const value = new Uint8Array(res.value)
				if (value[0] === 0x1 && value[1] === 0xf) {
					clearTimeout(timeout)
					resolve(value[2] === 0x0)
				}
			})
		})
	}

	// 断开连接
	async disconnect() {
		if (this.deviceId) {
			await wx.closeBLEConnection({
				deviceId: this.deviceId
			})
			this.deviceId = ''
		}
	}
}

export default BleService